/*! iNoBounce - v0.2.0
 * https://github.com/lazd/iNoBounce/
 * Copyright (c) 2013 Larry Davis <lazdnet@gmail.com>; Licensed BSD */
(function (global) {
  // Stores the Y position where the touch started
  var startY = 0;

  // Store enabled status
  var enabled = false;

  var supportsPassiveOption = false;
  try {
    var opts = Object.defineProperty({}, "passive", {
      get: function () {
        supportsPassiveOption = true;
      },
    });
    window.addEventListener("test", null, opts);
  } catch (e) {}

  var handleTouchmove = function (evt) {
    // Get the element that was scrolled upon
    var el = evt.target;

    // Allow zooming
    var zoom = window.innerWidth / window.document.documentElement.clientWidth;
    if (evt.touches.length > 1 || zoom !== 1) {
      return;
    }

    // Check all parent elements for scrollability
    while (el !== document.body && el !== document) {
      // Get some style properties
      var style = window.getComputedStyle(el);

      if (!style) {
        // If we've encountered an element we can't compute the style for, get out
        break;
      }

      // Ignore range input element
      if (el.nodeName === "INPUT" && el.getAttribute("type") === "range") {
        return;
      }

      var scrolling = style.getPropertyValue("-webkit-overflow-scrolling");
      var overflowY = style.getPropertyValue("overflow-y");
      var height = parseInt(style.getPropertyValue("height"), 10);

      // Determine if the element should scroll
      var isScrollable =
        scrolling === "touch" &&
        (overflowY === "auto" || overflowY === "scroll");
      var canScroll = el.scrollHeight > el.offsetHeight;

      if (isScrollable && canScroll) {
        // Get the current Y position of the touch
        var curY = evt.touches ? evt.touches[0].screenY : evt.screenY;

        // Determine if the user is trying to scroll past the top or bottom
        // In this case, the window will bounce, so we have to prevent scrolling completely
        var isAtTop = startY <= curY && el.scrollTop === 0;
        var isAtBottom =
          startY >= curY && el.scrollHeight - el.scrollTop === height;

        // Stop a bounce bug when at the bottom or top of the scrollable element
        if (isAtTop || isAtBottom) {
          evt.preventDefault();
        }

        // No need to continue up the DOM, we've done our job
        return;
      }

      // Test the next parent
      el = el.parentNode;
    }

    // Stop the bouncing -- no parents are scrollable
    evt.preventDefault();
  };

  var handleTouchstart = function (evt) {
    // Store the first Y position of the touch
    startY = evt.touches ? evt.touches[0].screenY : evt.screenY;
  };

  var enable = function () {
    // Listen to a couple key touch events
    window.addEventListener(
      "touchstart",
      handleTouchstart,
      supportsPassiveOption ? { passive: false } : false
    );
    window.addEventListener(
      "touchmove",
      handleTouchmove,
      supportsPassiveOption ? { passive: false } : false
    );
    enabled = true;
  };

  var disable = function () {
    // Stop listening
    window.removeEventListener("touchstart", handleTouchstart, false);
    window.removeEventListener("touchmove", handleTouchmove, false);
    enabled = false;
  };

  var isEnabled = function () {
    return enabled;
  };

  // Enable by default if the browser supports -webkit-overflow-scrolling
  // Test this by setting the property with JavaScript on an element that exists in the DOM
  // Then, see if the property is reflected in the computed style
  var testDiv = document.createElement("div");
  document.documentElement.appendChild(testDiv);
  testDiv.style.WebkitOverflowScrolling = "touch";
  var scrollSupport =
    "getComputedStyle" in window &&
    window.getComputedStyle(testDiv)["-webkit-overflow-scrolling"] === "touch";
  document.documentElement.removeChild(testDiv);

  if (scrollSupport) {
    enable();
  }

  // A module to support enabling/disabling iNoBounce
  var iNoBounce = {
    enable: enable,
    disable: disable,
    isEnabled: isEnabled,
  };

  if (typeof module !== "undefined" && module.exports) {
    // Node.js Support
    module.exports = iNoBounce;
  }
  if (typeof global.define === "function") {
    // AMD Support
    (function (define) {
      define("iNoBounce", [], function () {
        return iNoBounce;
      });
    })(global.define);
  } else {
    // Browser support
    global.iNoBounce = iNoBounce;
  }
})(this);
